import socket
import time
from typing import Dict


def readall(connection: socket.socket) -> bytes:
    buff = bytes()
    buff_size = 4096
    while True:
        part = connection.recv(buff_size)
        buff += part
        if len(part) < buff_size:
            break
    return buff


def home_page() -> str:
    return """
        <html>
            <head>
                <title>主页</title>
            </head>
            <body>
                <h1>
                    欢迎来到我的网站
                </h1>
                小工具：<a href="/tool/current-time">查询当前时间</a>
            </body>
        </html>
    """


def show_time_page() -> str:
    return f"""
        <html>
            <head>
                <title>当前时间</title>
            </head>
            <body>
                <h1>
                    当前时间：{time.asctime()}
                </h1>
            </body>
        </html>
    """


def route_request(method: str, resource: str, headers: Dict[str, str], body: str) -> str:
    if resource == '/':
        return home_page()
    if resource == '/tool/current-time':
        return show_time_page()
    else:
        return """
            <html>
                <body>
                    <h1>Unknown URL</h1>
                </body>
            </html>
        """


def handle_request(method: str, resource: str, version: str, headers: Dict[str, str], body: str) -> str:
    print(f'method: [{method}], resource: [{resource}], version: [{version}]')
    print(f'headers: [{headers}]')
    resp = ''
    resp += f'{version} 200 OK\r\n'
    resp += f'Content-Type: text/html; charset=utf-8'
    resp += '\r\n'
    resp_body = route_request(method=method, resource=resource, headers=headers, body=body)
    resp += resp_body
    return resp


def headers_list_to_map(header_list: list[str]) -> Dict[str, str]:
    headers = {}
    for header in header_list:
        parts = header.split(': ', 1)
        headers[parts[0]] = parts[1]
    return headers


def handle_connection(connection: socket.socket):
    request = readall(connection).decode('utf-8')
    non_body_and_body = request.split('\r\n\r\n')
    non_body_lines = non_body_and_body[0].split('\r\n')
    req_line = non_body_lines[0]
    header_list = non_body_lines[1:]
    headers = headers_list_to_map(header_list)
    req_line_parts = req_line.split(' ')
    method = req_line_parts[0]
    resource = req_line_parts[1]
    version = req_line_parts[2]
    response = handle_request(
        method=method, resource=resource, version=version, headers=headers, body=non_body_and_body[1]
    )
    print(f'Response: {response}')
    connection.send(response.encode('utf-8'))


def server():
    acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    with acceptor:
        acceptor.bind(('', 8080))
        acceptor.listen(128)
        while True:
            connection, client_address = acceptor.accept()
            with connection:
                try:
                    handle_connection(connection)
                except Exception as e:
                    print(f'Unhandled Exception: {e}')


if __name__ == '__main__':
    server()
